﻿// -----------------------------------------------------------------------
// <copyright file="Task.cs" company="The Usual Dosage">
// © 2013 by Matthew M. Martin
// </copyright>
// -----------------------------------------------------------------------

namespace Cadence.NET
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using Cadence.NET.Attributes;
    using Cadence.NET.BaseClasses;
    using Cadence.NET.Notifications;
    using Cadence.NET.Interfaces;

    /// <summary>
    /// Abstract representation of a single task which is executed by the CadenceTaskManager.
    /// </summary>
    public abstract class Task
    {
        #region Properties

        /// <summary>
        /// Gets or sets the task context.
        /// </summary>
        /// <value>
        /// The task context.
        /// </value>
        public ITaskContext TaskContext { get; set; }

        /// <summary>
        /// Task will only be performed on days, times, or ranges specified in the calendars. More than one calendar
        /// can be defined for a task.
        /// </summary>
        /// <value>
        /// The calendar.
        /// </value>
        public List<ICalendar> Calendars { get; set; }

        /// <summary>
        /// Gets a value indicating whether this task is runnable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this task is runnable; otherwise, <c>false</c>.
        /// </value>
        public bool IsRunnable
        {
            get
            {
                bool canRun = true;
                if (Calendars != null)
                {
                    Calendars.ForEach(c =>
                    {
                        if (!c.CanRun())
                            canRun = false;
                    });
                }
                return canRun;
            }
        }

        #endregion Properties

        #region Events and Delegates

        /// <summary>
        /// The event handler for Task Started.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="context">The context.</param>
        public delegate void TaskStartedEventHandler(object sender, ITaskContext context);

        /// <summary>
        /// Occurs when [task started].
        /// </summary>
        public event TaskStartedEventHandler TaskStarted;

        /// <summary>
        /// The event handler for Task Completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="context">The context.</param>
        public delegate void TaskCompletedEventHandler(object sender, ITaskContext context);

        /// <summary>
        /// Occurs when [task completed].
        /// </summary>
        public event TaskCompletedEventHandler TaskCompleted;

        /// <summary>
        /// The event handle for Task Error.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="context">The context.</param>
        public delegate void TaskErrorEventHandler(object sender, ITaskContext context);

        /// <summary>
        /// Occurs when [task error].
        /// </summary>
        public event TaskErrorEventHandler TaskError;

        #endregion Events and Delegates

        #region Methods & Event Handlers

        /// <summary>
        /// Raises the <see cref="E:TaskStarted"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> task containing the event data.</param>
        protected virtual void OnTaskStarted(ITaskContext context)
        {
            object attrib = this.GetType().GetCustomAttributes(true).Where(a => (a is NotificationBehavior)).FirstOrDefault();
            if (attrib != null)
            {
                // Fire the notifications off asynchronously. We don't want to halt the process while
                // trying to send
                NotificationManager manager = new NotificationManager();
                var thread = new Thread(
                    () => manager.ProcessNotification(context, (attrib as NotificationBehavior), NotificationBehavior.NotifyEvent.TaskStart));
                thread.Start();
            }

            if (TaskStarted != null)
                TaskStarted(this, context);
        }

        /// <summary>
        /// Called when [task completed].
        /// </summary>
        /// <param name="context">The context.</param>
        protected virtual void OnTaskCompleted(ITaskContext context)
        {
            object attrib = this.GetType().GetCustomAttributes(true).Where(a => (a is NotificationBehavior)).FirstOrDefault();
            if (attrib != null)
            {
                // Fire the notifications off asynchronously. We don't want to halt the process while
                // trying to send
                NotificationManager manager = new NotificationManager();
                var thread = new Thread(
                    () => manager.ProcessNotification(context, (attrib as NotificationBehavior), NotificationBehavior.NotifyEvent.TaskStop));
                thread.Start();
            }

            if (TaskCompleted != null)
                TaskCompleted(this, context);
        }

        /// <summary>
        /// Called when [task error].
        /// </summary>
        /// <param name="context">The context.</param>
        protected virtual void OnTaskError(ITaskContext context)
        {
            object attrib = this.GetType().GetCustomAttributes(true).Where(a => (a is NotificationBehavior)).FirstOrDefault();
            if (attrib != null)
            {
                // Fire the notifications off asynchronously. We don't want to halt the process while
                // trying to send
                NotificationManager manager = new NotificationManager();
                var thread = new Thread(
                    () => manager.ProcessNotification(context, (attrib as NotificationBehavior), NotificationBehavior.NotifyEvent.TaskError));
                thread.Start();
            }

            if (TaskError != null)
                TaskError(this, context);
        }

        /// <summary>
        /// Performs the task.
        /// </summary>
        /// <returns>True if the task succeeded, false if the task failed</returns>
        public abstract void PerformTask(ITaskContext context);

        #endregion Methods & Event Handlers
    }
}
